package database;

import java.util.ArrayList;

import database.attset.SetAttribute;
import database.fd.FunctionalDependency;
import database.fd.ListFunctionDependency;
import database.node.ListNode;
import database.relation.Relation;

public class Schema {
	public static UniversalRelation uRelation = new UniversalRelation();
	public static ArrayList<Relation> listRelation = new ArrayList<Relation>();
	public static ListFunctionDependency listFunctionDependency = new ListFunctionDependency();
	public static boolean alreadyAnalysis = false;
	
	public void printAllRelation() {
		for(int i = 0; i < listRelation.size(); i++) {
			Relation r = listRelation.get(i);
			System.out.print(r.getRname());
			System.out.print("(");
			for(int j = 0; j < r.size() - 1; j ++) {
				System.out.print(uRelation.findAttribute(r.get(j), i).attName);
				System.out.print(", ");
			}
			System.out.print(uRelation.findAttribute(r.get(r.size() - 1), i).attName);
			System.out.println(")");
		}
	}
	
	public void printAllFd() {
		for(int i = 0; i < listFunctionDependency.size(); i++) {
			listFunctionDependency.get(i).printFd(); System.out.println();
		}
	}
	
	public void printUniversalRelation() {
		for(int i = 0; i < uRelation.size(); i++) {
			ListNode ln = uRelation.get(i);
			ln.printListNode(); System.out.println();
		}
	}
	
	public static ListFunctionDependency getMinimalCoverFD(ListFunctionDependency listFD){
	    ListFunctionDependency returnListFD = new ListFunctionDependency();
          // buoc 1: loai bo du thua ve phai
        for (FunctionalDependency fd : listFD){
            SetAttribute left = fd.getLeft();
            SetAttribute right = fd.getRight();
            for (Integer att : right){
                FunctionalDependency tmpFD = new FunctionalDependency();
                SetAttribute tmpRight = new Relation();

                tmpRight.add(att);
                tmpFD.setLeft((SetAttribute) left.clone());
                tmpFD.setRight(tmpRight);
                returnListFD.add(tmpFD);
            }
        }

          // buoc 2: loai bo du thua ve trai
        int i = 0;
        while (i<returnListFD.size()){
            ArrayList<SetAttribute> tmp_lsSetAtt = returnListFD.get(i).getLeft().getListMaxSubset();

            boolean isRedundance = false;
            int j = 0;
            while (!isRedundance && j<tmp_lsSetAtt.size()){
                FunctionalDependency  tmp_fd = new FunctionalDependency();
                tmp_fd.setLeft(tmp_lsSetAtt.get(j));
                tmp_fd.setRight((SetAttribute) returnListFD.get(i).getRight().clone());
                  // o day su dung listFD
                if (isHoldingFd(tmp_fd, listFD)){
                    isRedundance = true;
                      // them fd moi vao tap phu thuoc ham
                    returnListFD.add(tmp_fd);
                      // loai bo phu thuoc ham thu i dang set
                    returnListFD.remove(i);
                } else {
                    j++;
                }
            }
              // neu co du thua thi phu thuoc ham thu i se bi xoa va khong can phai i++
            if (!isRedundance){
                i++;
            }
        }

          // buoc 3: loai bo du thua phu thuoc ham
        i = 0;
        while(i<returnListFD.size()){
            ListFunctionDependency tmp_lsFD = returnListFD.clone();
            FunctionalDependency tmp_fd = tmp_lsFD.get(i);
            tmp_lsFD.remove(i);

              // neu fd dang xet la member cua tap fd da bo di fd do thi fd do la du thua
              // tmp_lsFD la returnListFD da bo di fd thu i neu khong can i++
            if (isHoldingFd(tmp_fd, tmp_lsFD)){
                returnListFD = tmp_lsFD;
            } else {
                i++;
            }
        }

        System.gc();
        return returnListFD;
    }
	
	/**
     * nếu fd holding trong tập listFd thì return true
     * ko thì return false
     */
    public static boolean isHoldingFd(FunctionalDependency fd, ListFunctionDependency listFd) {
        ListFunctionDependency tmpListFd = new ListFunctionDependency();

        for(int i = 0; i < listFd.size(); i++) {
            FunctionalDependency tmpFd = new FunctionalDependency();
            tmpFd.setLeft((SetAttribute) listFd.get(i).getLeft().clone());
            tmpFd.setRight((SetAttribute) listFd.get(i).getRight().clone());
            tmpListFd.add(tmpFd);
        }

        SetAttribute closureFdLeft = fd.getLeft(    ).getClosure_Extra(tmpListFd);
        if(!closureFdLeft.isSuperSet(fd.getRight())) {
            return false;
        }
        return true;
    }
    
    public static ListFunctionDependency mergeFD(ListFunctionDependency listFd) {
        ListFunctionDependency tmp_lsFD = listFd.clone();
        ListFunctionDependency returnLsFD = new ListFunctionDependency();
        
        int i = 0;
        while (i < tmp_lsFD.size()) {
            FunctionalDependency tmp_fd = tmp_lsFD.get(0).clone();
            tmp_lsFD.remove(0);
            
            int k = 0;
            while (k < tmp_lsFD.size()) {
                if (tmp_fd.left.isEqual(tmp_lsFD.get(k).left)) {
                    for (Integer integ : tmp_lsFD.get(k).right) {
                        tmp_fd.right.add(integ);
                    }
                    tmp_lsFD.remove(k);
                } else {
                    k++;
                }
            }
            
            returnLsFD.add(tmp_fd);
        }
        
        return returnLsFD;
    }
//	// test
//	public static void main(String[] args) {
//	    SetAttribute set1 = new SetAttribute(); set1.add(0);
//	    SetAttribute set2 = new SetAttribute(); set2.add(1); set2.add(2);
//	    
//	    ArrayList<FunctionalDependency> lfd = null;
//	    ArrayList<FunctionalDependency> fd1 = new ArrayList<FunctionalDependency>();
//	    
//	    FunctionalDependency fd = new FunctionalDependency();
//	    fd.left.add(0); fd.right.add(1); fd.right.add(2);
//	    fd1.add(fd);
//	    
//	    lfd = (ArrayList<FunctionalDependency>) fd1.clone();
//	    
//	    fd1.get(0).printFd();
//	    lfd.get(0).printFd();
//	    
//	    fd1.get(0).right.remove(1);
//	    fd1.get(0).printFd();
//        lfd.get(0).printFd();
//	    
//	    ArrayList<FunctionalDependency> fd2 = new ArrayList<FunctionalDependency>() {
//
//	        @Override
//	        public Object clone() {
//	            ArrayList<FunctionalDependency> returnListFd = new ArrayList<FunctionalDependency>();
//	            for(FunctionalDependency fd : this) {
//	                returnListFd.add(fd.clone());
//	            }
//	            return returnListFd;
//	        }
//	        
//	    };
//	    
//	    FunctionalDependency _fd = new FunctionalDependency();
//	    _fd.left.add(0); _fd.right.add(1); _fd.right.add(2);
//	    
//	    fd2.add(_fd);
//	    lfd = (ArrayList<FunctionalDependency>) fd2.clone();
//	    
//	    fd2.get(0).printFd();
//	    lfd.get(0).printFd();
//	    
//	    fd2.get(0).right.remove(1);
//        fd2.get(0).printFd();
//        lfd.get(0).printFd();
//	    
//	}
}
